package com.darkevil.jdspider.service

import com.darkevil.jdspider.entity.Product
import com.darkevil.jdspider.mapper.ProductMapper
import org.apache.ibatis.session.SqlSessionFactory
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.scheduling.annotation.Async
import org.springframework.stereotype.Service

@Service
class QueueService {
    private val logger = LoggerFactory.getLogger(this.javaClass)
    @Autowired
    private lateinit var productMapper: ProductMapper
    @Autowired
    private lateinit var sqlSessionFactory: SqlSessionFactory

    companion object {
        var productQueue: MutableList<Product> = arrayListOf()
    }

    /**
     * 加入队列
     */
    fun addProductQueue(productList: MutableList<Product>) {
        var size = 0
        synchronized(productQueue) {
            productQueue.addAll(productList)
            size = productQueue.size
        }
        if (size in 50000..100000) {
            Thread.sleep(5000)
        } else if (size > 100000) {
            Thread.sleep(10000)
        }
    }

    /**
     * 商品队列去重
     */
    private fun distinctProductQueue() {
        logger.debug("去重前 product queue size=${productQueue.size}")
        val tmpList = productQueue.distinctBy { it.id }
        productQueue.clear()
        productQueue.addAll(tmpList)
        logger.debug("去重后 product queue size=${productQueue.size}")
    }

    /**
     * 商品队列入库
     */
    @Async
    fun productQueueSave() {
        logger.info("product saver 启动")
        val saveList = arrayListOf<Product>()
        var count = 0
        var tmpTag = 0
        // postgresql数据库对参数数量有限制
        val subListCount = if (sqlSessionFactory.configuration.databaseId == "postgresql") {
            32767 / Product::class.java.declaredFields.size
        } else {
            10000
        }
        while (true) {

            if (productQueue.isNotEmpty()) {
                val start = System.currentTimeMillis()
                synchronized(productQueue) {
                    distinctProductQueue()
                    logger.debug("当前 product queue size = ${productQueue.size}")
                    logger.debug("product 开始保存")
                    if (productQueue.size > subListCount) {
                        val tmpList = productQueue.subList(0, subListCount)
                        saveList.addAll(tmpList)
                        // 该操作会清空截取的productQueue
                        tmpList.clear()
                    } else {
                        saveList.addAll(productQueue)
                        productQueue.clear()
                    }
                }
                try {
                    productMapper.batchReplace(saveList)
                    count += saveList.size
                    logger.debug("product 保存完成 耗时:${System.currentTimeMillis() - start} ms 共保存${saveList.size}条")
                    saveList.clear()
                    val tmpParam = count / 10000
                    if (tmpParam % 5 == 0 && tmpTag != tmpParam) {
                        tmpTag = tmpParam
                        logger.info("已经入库 $count 条")
                    }
                } catch (e: Exception) {
                    logger.error("product queue 保存失败", e)
                    // 保存失败要把未写入的数据重新放入内存
                    synchronized(productQueue) {
                        productQueue.addAll(saveList)
                    }
                }

            } else {
                Thread.sleep(1000)
            }
        }
    }

}